﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace iMario
{
    public class CharacterManager : EntityManager
    {
        //Mục đích
        //  - Tập trung các thuộc tính và phương thức xử lí liên quan đến character 
        //  - Sử dụng List prototypes làm danh sách các character được tạo lập, trong đó đối tượng thứ (prototypes.Count - 1) là character đang được sử dụng và còn sống
        //  - Điều khiển nhân vật hiện tại thông qua List prototypes và chỉ số nhân vật hiện tại đang được điều khiển _currentCharacter
        
        //Danh sách các thuộc tính và ý nghĩa
        static public MapManager mapManager;                    //Đại diện cho đối tượng MapManager của game
        static public ContentManager content;                   //Đại diện cho Content của game

        private int _currentCharacter;                          //Character hiện tại đang được sử dụng
        public int currentCharacter
        {
            get { return _currentCharacter; }
            set { _currentCharacter = value; }
        }

        private List<KindOfSprite> _kindOfCharacter;            //Danh sách các loại character
        public List<KindOfSprite> kindOfCharacter
        {
            get { return _kindOfCharacter; }
            set { _kindOfCharacter = value; }
        }

        //Danh sách các phương thức và ý nghĩa
        //Hàm dựng mặc định
        //  1. Tham số truyền vào: Không có
        //  2. Giá trị trả về: Không có
        public CharacterManager()
        {
            //Hướng xử lí
            //  1. Khởi tạo danh sách prototypes
            //  2. Khởi tạo danh sách _kindOfCharacter


            //Tiến hành
            //  1. Khởi tạo danh sách prototypes
            prototypes = new List<GameObject>();

            //  2. Khởi tạo danh sách _kindOfCharacter
            _kindOfCharacter = new List<KindOfSprite>();
        }

        //Hàm tạo bản đồ mới từ những bản đồ có trong prototypes
        //  1. Tham số truyền vào: Không có
        //  2. Giá trị trả về: Không có
        public void CreateObject()
        {
            //Hướng xử lí
            //  1. Thực hiện clone 1 đối tượng GameObject từ đối tượng cuối cùng của prototypes


            //Tiến hành
            //  1. Thực hiện clone 1 đối tượng GameObject từ đối tượng cuối cùng của prototypes
            prototypes.Add((GameObject)prototypes[prototypes.Count - 1].Clone());
        }

        //Hàm khởi tạo các thuộc tính và prototypes
        //  1. Tham số truyền vào:
        //  2. Giá trị trả về: Không có
        public void Initial()
        { 
            //Hướng xử lí
            //  1. Thiết lập giá trị ban đầu cho biến currentCharacter
            //  2. Gán các đối tượng KindOfSprite vào _kindOfCharacter


            //Tiến hành
            //  1. Thiết lập giá trị ban đầu cho biến currentCharacter
            currentCharacter = 0;

            //  2. Gán các đối tượng KindOfSprite vào _kindOfCharacter
            KindOfSprite _kind = new KindOfSprite(@"Mario", 5, 150, true, new Point(32, 64), new Point(4, 10));
            _kindOfCharacter.Add(_kind);
        }

        //Hàm Load các resource liên quan của các thuộc tính trong đối tượng CharacterManager
        //  1. Tham số truyền vào: Không có
        //  2. Giá trị trả về: Không có
        public void LoadContent()
        {
            //Hướng xử lí
            //Nếu giá trị thuộc tính _content khác null => Thực hiện tiếp các lệnh bên dưới
            //  1. Gọi hàm LoadContent của các đối tượng KindOfSprite nằm trong List _kindOfCharacter
            //  2. Khởi tạo đối tượng Character đầu tiên cũng là nhân vật được sử dụng hiện tại và thêm vào List prototypes
            //  3. Thiết lập loại sprite cho đối tượng Character đầu tiên trong prototypes


            //Tiến hành
            //Nếu giá trị thuộc tính _content khác null => Thực hiện tiếp các lệnh bên dưới
            if (content == null)
                return;

            //  1. Gọi hàm LoadContent của các đối tượng KindOfSprite nằm trong List _kindOfCharacter
            for (int i = 0; i < _kindOfCharacter.Count; i++)
            {
                _kindOfCharacter[i].LoadContent(KindOfSprite.LEFT);
                _kindOfCharacter[i].LoadContent(KindOfSprite.RIGHT);
                _kindOfCharacter[i].LoadContent(KindOfSprite.JUMPLEFT);
                _kindOfCharacter[i].LoadContent(KindOfSprite.JUMPRIGHT);
            }

            //  2. Khởi tạo đối tượng Character đầu tiên cũng là nhân vật được sử dụng hiện tại và thêm vào List prototypes
            GameObject _firstCharacter = new Character();
            prototypes.Add((GameObject)_firstCharacter);

            //  3. Thiết lập loại sprite cho đối tượng Character đầu tiên trong prototypes
            ((Character)prototypes[prototypes.Count - 1]).SetKindOfSprite(_kindOfCharacter[0]);

            //Tìm kiếm vị trí bắt đầu của nhân vật
            for (int row = 0; row < Map.MapHeight; row++)
                for (int collumn = 0; collumn < 25; collumn++)
                    if (mapManager.currentMap.mapMatrix[row][collumn] == mapManager.currentMap.nTile - 3)
                    {
                        //Thiết lập vị trí bắt đầu của nhân vật - đối tượng đầu tiên trong List prototypes
                        SetGraphicLocation(new Point(collumn * Map.TileSize, row * Map.TileSize - ((Character)prototypes[currentCharacter]).kind.size.Y));

                        break;
                    }
        }

        //Hàm xử lí logic cho nhân vật
        //  1. Tham số truyền vào:
        //      - KeyboardState _keyboard: Đại diện cho trạng thái hiện tại của keyboard
        //      - MouseState _mouse: Đại diện cho trạng thái hiện tại của mouse
        //      - GameTime _gameTime;
        //  2. Giá trị trả về: Không có
        public void Update(KeyboardState _keyboard, MouseState _mouse, GameTime _gameTime)
        { 
            //Hướng xử lí
            //Nếu mapManager != null và mapManager.currentMap != null => Tiến hành các lệnh bên dưới


            //Tiến hành
            //Nếu mapManager != null và mapManager.currentMap != null => Tiến hành các lệnh bên dưới
            if (mapManager == null || mapManager.currentMap == null)
                return;

            prototypes[currentCharacter].Update(_keyboard, _mouse, _gameTime);

            if (((Character)prototypes[currentCharacter]).graphicLocation.Y >= Map.WindowHeigh - ((Character)prototypes[currentCharacter]).kind.size.Y)
                MakeCurrrentCharacterDied();
        }

        //Hàm xử lí thao tác vẽ nhân vật
        //  1. Tham số truyền vào:
        //      - SpriteBatch _spriteBatch
        //      - GameTime _gameTime
        //  2. Giá trị trả về: Không có
        public void Draw(SpriteBatch _spriteBatch, GameTime _gameTime)
        { 
            //Hướng xử lí
            //Nếu mapManager != null và mapManager.currentMap != null => Tiến hành các lệnh bên dưới


            //Tiến hành
            //Nếu mapManager != null và mapManager.currentMap != null => Tiến hành các lệnh bên dưới
            if (mapManager == null || mapManager.currentMap == null)
                return;

            prototypes[currentCharacter].Draw(_spriteBatch, _gameTime);
        }

        //Hàm thiết lập giá trị _content cho đối tượng CharacterManager
        //  1. Tham số truyền vào
        //  2. Giá trị trả về: Không có
        public void SetContent(ContentManager _inputContent)
        {
            //Thiết lập content cho lớp đối tượng CharacterManager
            content = _inputContent;

            //Thiết lập content cho lớp đối tượng KindOfSprite
            KindOfSprite.SetContent(_inputContent);
        }

        //Hàm xử lí khi nhân vật hiện tại đang được điều khiển bị dead
        //  1. Tham số truyền vào: Không có
        //  2. Giá trị trả về: Không có
        public void MakeCurrrentCharacterDied()
        {
            //Hướng xử lí
            //  1. Thiết lập giá trị cho cờ hiệu isDead của nhân vật hiện tại đang được điều khiển
            //  2. Thực hiện Clone 1 đối tượng Character từ đối tượng hiện tại (thuộc tính isDead của đối tượng mới là true) và add vào prototypes
            //  3. Gán giá trị cho biến currentCharacter
            

            //Tiến hành
            //  1. Thiết lập giá trị cho cờ hiệu isDead của nhân vật hiện tại đang được điều khiển
            ((Character)prototypes[currentCharacter]).isDead = true;

            //  2. Thực hiện Clone 1 đối tượng Character từ đối tượng hiện tại (thuộc tính isDead của đối tượng mới là true) và add vào prototypes
            this.CreateObject();

            //  3. Gán giá trị cho biến currentCharacter
            currentCharacter = prototypes.Count - 1;
        }

        //Hàm thiết lập vị trí trên màn hình game cho nhân vật hiện tại đang được điều khiển
        //  1. Tham số truyền vào
        //      - Point _location: Hoành độ và tung độ của nhân vật
        //  2. Giá trị trả về: Không có
        public void SetGraphicLocation(Point _location)
        {
            ((Character)prototypes[currentCharacter]).graphicLocation = _location;
        }

        //Hàm thiết lập biến đại diện cho lớp đối tượng MapManager
        //  1. Tham số truyền vào:
        //      - MapManager _inputMapManager
        //  2. Giá trị trả về: Không có
        public void SetMapManager(MapManager _inputMapManager)
        {
            //Thiết lập giá trị mapManager cho lớp đối tượng CharacterManager
            mapManager = _inputMapManager;

            //Thiết lập giá trị mapManager cho lớp đối tượng Character
            Character.SetMapManager(mapManager);
        }
    }
}
